#pragma once
/*
	文件版本
*/
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <assert.h>
#include <fstream>

#include "../comm/log.hpp"
#include "../comm/util.hpp"

namespace ns_model
{
	using namespace std;
	using namespace ns_log;
	using namespace ns_util;

	//题目信息
	struct Question
	{
		std::string number;	//题目编号，唯一
		std::string title;	//题目的标题
		std::string star;	//难度: 简单 中等 困难
		int cpu_limit;		//题目的时间要求(S)
		int mem_limit;		//题目的空间要去(KB)
		std::string  desc;	//题目的描述
		std::string header;	//题目预设给用户在线编辑器的代码
		std::string tail;	//题目的测试用例，需要和header拼接，形成完整代码
	};

	const string questions_list = "./questions/questions.list";
	const string questions_path = "./questions/";

	class Model
	{
		private:
		std::unordered_map<std::string,Question> _QuestionList;

		public:
		Model()
		{
			assert(LoadQuestionList(questions_list));
		}
		~Model(){}

		//加载题目
		bool LoadQuestionList(const std::string &question_list)
		{
			//先获取questions.list中的信息，再到详细的题目文件获取
			ifstream in(questions_list);
			if(!in.is_open())
			{
				LOG(FATAL) << " 加载题库失败,请检查是否存在题库文件" << "\n";
				return false;
			}

			string line;
			while (getline(in,line))
			{
				vector<string> tokens;
				//进行分词处理
				StringUtil::SplitStr(line,&tokens," ");
				if(tokens.size() != 5)
				{
					LOG(WARNING) << "加载部分题目失败, 请检查文件格式" << endl;
					continue;
				}
				// 1 判断回文数 简单 1 30000
				Question q;
				q.number = tokens[0];
				q.title = tokens[1];
				q.star = tokens[2];
				q.cpu_limit = atoi(tokens[3].c_str());
				q.mem_limit = atoi(tokens[4].c_str());

				string path = questions_path;
				path += q.number;
				path += "/";

				FileUtil::ReadFile(path+"desc.txt",&(q.desc),true);
				FileUtil::ReadFile(path+"header.cc",&(q.header),true);
				FileUtil::ReadFile(path+"tail.cc",&(q.tail),true);

				_QuestionList.insert({q.number,q});
			}

			LOG(INFO) << "加载题库...成功!" << "\n";
			in.close();
			return true;
		}

		//获取所有题目
		bool GetAllQuestions(vector<Question> *out)
		{
			if(_QuestionList.size() == 0)
			{
				LOG(ERROR) << "用户获取题库失败" << endl;
				return false;
			}
			for(const auto &q : _QuestionList)
			{
				out->push_back(q.second);
			}
			return true;
		}

		//获取单个题目
		bool GetOneQuestion(const std::string &number, Question *q)
		{
			const auto& it = _QuestionList.find(number);
			if(it == _QuestionList.end())
			{
				LOG(ERROR) << "用户获取题目失败, 题目编号: " << number << endl;
				return false;
			}
			(*q) = it->second;
			return true;
		}
	};
}